#ifndef Net_SocketAddress_INCLUDED
#define Net_SocketAddress_INCLUDED

#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdlib.h>

#include "cpputils.h"

using std::string;

class SocketAddress
{
public:
    SocketAddress():m_port(0),m_af(-1)
    {}

    SocketAddress(const string& ip,unsigned int port)
    :m_ip(ip),m_port(port)
    {
        trim(m_ip);
        m_af    = calAf(m_ip,int2a(m_port));
    }

    SocketAddress(struct sockaddr_storage& addr)
    {
        char host[NI_MAXHOST] = {0};
        char port[NI_MAXSERV] = {0};
        struct sockaddr *pAddr = (struct sockaddr *)&addr;
        getnameinfo(pAddr,NI_MAXHOST,host,NI_MAXHOST,port,NI_MAXSERV,NI_NUMERICHOST|NI_NUMERICSERV);

        m_ip    = host;
        m_port  = atoi(port);
        m_af    = calAf(m_ip,port);
    }
    
    unsigned int port()
    {return m_port;}

    const string& ip()
    {return m_ip;}
    
    int af() const
    {
        return m_af;
    }

    struct sockaddr_storage addr() const
    {
        struct sockaddr_storage addr;
        memset(&addr,0,sizeof(addr));

        if ( m_af == AF_INET )
        {
            struct sockaddr_in *in4 = (struct sockaddr_in*)&addr;

            in4->sin_family         = m_af;
            in4->sin_port           = htons(m_port);
            inet_pton(m_af,m_ip.c_str(),&in4->sin_addr);
        }
        else if ( m_af == AF_INET6 )
        {
            struct sockaddr_in6 *in6 = (struct sockaddr_in6*) &addr;
            in6->sin6_family        = m_af;
            in6->sin6_port          = htons(m_port);
            inet_pton(m_af, m_ip.c_str(), &in6->sin6_addr);
        }

        return addr;
    }

    static unsigned int length()
    {
        return sizeof(struct sockaddr_storage);
    }

    static SocketAddress peerAddress(int fd)
    {
        if ( fd < 0)
            return SocketAddress();
        
        struct sockaddr_storage addr;
        unsigned int saLen = sizeof(addr);
        memset(&addr,0,saLen);
        struct sockaddr* pSA = (struct sockaddr*)&addr;

        ::getpeername(fd, pSA, &saLen);
        return SocketAddress(addr);
    }
private:
    static int calAf(const string& ip, const string& port)
    {
        struct addrinfo *result = NULL;
        struct addrinfo adinfo;
        memset(&adinfo,0,sizeof(adinfo));
        adinfo.ai_family      = AF_UNSPEC;
        adinfo.ai_socktype    = 0;
        adinfo.ai_flags       = AI_ADDRCONFIG;
        adinfo.ai_protocol    = 0;
        adinfo.ai_canonname   = NULL;
        adinfo.ai_addr        = NULL;
        adinfo.ai_next        = NULL;

        int ret = getaddrinfo(ip.c_str(),port.c_str(), &adinfo, &result);
        int af = -1;
        if ( ret != 0 )
        {
            af = -1;
        }
        else if ( result != NULL )
        {
            af = result->ai_family;
            freeaddrinfo(result);
        }

        return af;
    }
private:
    // 都是主机字节序的
    string          m_ip;
    unsigned int    m_port;
    int             m_af;
};

#endif




